/**
 * Copyright 2002-2006 the original author or authors.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package opentss;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

/**
 * Writer on top of channel.
 * 
 * @author <a href="mailto:max.h.chen@hotmail.com">Max Chen</a>
 */
public class ChannelWriter implements Writer {
	
	private SocketChannel channel;
	private ByteBuffer writeBuffer;
	
	public ChannelWriter(SocketChannel channel, int writeBufSize) {
		this.channel = channel;
		this.writeBuffer = ByteBuffer.allocate(writeBufSize);
	}
	
	public void writeByte(byte b) throws IOException {
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		StreamUtil.writeByte(bos, b);
		
		write(bos.toByteArray(), 0, bos.size());
	}
	
	public void writeBoolean(boolean b) throws IOException {
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		StreamUtil.writeBoolean(bos, b);
		
		write(bos.toByteArray(), 0, bos.size());
	}
	
	public void writeChar(char c) throws IOException {
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		StreamUtil.writeChar(bos, c);
		
		write(bos.toByteArray(), 0, bos.size());
	}
	
	public void writeShort(short s) throws IOException {
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		StreamUtil.writeShort(bos, s);
		
		write(bos.toByteArray(), 0, bos.size());
	}
	
	public void writeInt(int i) throws IOException {
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		StreamUtil.writeInt(bos, i);
		
		write(bos.toByteArray(), 0, bos.size());
	}
	
	public void writeLong(long l) throws IOException {
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		StreamUtil.writeLong(bos, l);
		
		write(bos.toByteArray(), 0, bos.size());
	}
	
	public void writeFloat(float f) throws IOException {
		writeInt(Float.floatToIntBits(f));
	}
	
	public void writeDouble(double d) throws IOException {
		writeLong(Double.doubleToLongBits(d));
	}
	
	public void writeUTF(String str) throws IOException {
		if (str == null) {
            writeInt(-1);
            return ;
        }
        else if (str.length() == 0) {
            writeInt(0);
            return ;
        }
		byte[] buf = StreamUtil.toUTF(str);
		write(buf, 0, buf.length);
	}

	public void write(byte[] bytes, int offset, int length) throws IOException {
		if (bytes == null) {
		    throw new NullPointerException();
		} else if ((offset < 0) || (offset > bytes.length) || (length < 0) ||
			   ((offset + length) > bytes.length) || ((offset + length) < 0)) {
		    throw new IndexOutOfBoundsException();
		} else if (length == 0) {
		    return;
		}
		
		int remaining = 0;
		while (length > (remaining = writeBuffer.remaining())) {
			length -= remaining;
			writeBuffer.put(bytes, offset, remaining);
			offset += remaining;
			flush();
		}
		writeBuffer.put(bytes, offset, length);
	}
	
	public void flush() throws IOException {
		writeBuffer.flip();
		while (writeBuffer.hasRemaining())
			channel.write(writeBuffer);
		writeBuffer.clear();
	}

	public void close() {
		writeBuffer = null;
		
		try {
			channel.close();
        } catch (Throwable t) {
        }
	}
	
}
